package com.jy.importclient.handler;

import cn.hutool.core.util.ObjectUtil;
import com.jy.importclient.common.constants.ExpConstants;
import com.jy.importclient.common.constants.PrefixConstants;
import com.jy.importclient.common.dto.ReturnDto;
import com.jy.importclient.common.dto.VerifyFile;
import com.jy.importclient.common.enums.TaskStatusEnum;
import com.jy.importclient.common.util.FileUtil;
import com.jy.importclient.common.util.SnowFlakeUtil;
import com.jy.importclient.common.util.StringUtil;
import com.jy.importclient.common.vo.ReturnVo;
import com.jy.importclient.config.ThreadPoolConfig;
import com.jy.importclient.entity.ImportSubTask;
import com.jy.importclient.entity.ImportTaskLog;
import com.jy.importclient.support.HttpSupport;
import com.jy.importclient.support.SubTaskSupport;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @类名 SubtaskHandler
 * @描述 TODO
 * @作者 白条君
 * @创建日期 2023/4/27 14:37
 * @版本 1.0
 */
@Slf4j
@Component
public class SubtaskHandler {

    @Resource
    private ThreadPoolConfig threadPoolConfig;

    @Resource
    private SubTaskSupport subTaskSupport;

    @Resource
    private HttpSupport httpSupport;

    /**
     * 对于dat文件执行失败的情况，只能对文件大小或者记录行数不对的dat文件进行重试处理，无法对dat文件名错误的文件重试
     * 对于错误的dat文件名称，用户必须重新导入执行handle方法
     * @param returnDto
     */
    public void handle(ReturnDto returnDto) {
        //获取结果并进行反序列化得到importSubTasks
        List<ImportSubTask> importSubTasks = returnDto.getData();

        //importSubTasks可能为空
        if (ObjectUtil.isNull(importSubTasks)) {
            return;
        }

        //获取执行失败的dat文件
        List<String> fileNames = returnDto.getFileNames();

        //获取线程池执行器
        ThreadPoolExecutor executor = threadPoolConfig.threadPoolExecutor();

        //对于每一个子任务进行异步处理
        for (ImportSubTask importSubTask : importSubTasks) {
            //判断参数是否为空
            String fullFileName = importSubTask.getFileName();
            if (StringUtils.isEmpty(fullFileName)) {
                log.error(ExpConstants.PARAMS_EXP);
                continue;
            }

            //执行子任务，先对ver文件校验，再对dat文件校验
            executor.execute(() -> {
                try {
                    //创建子任务日志
                    ImportTaskLog importTaskLog = new ImportTaskLog();
                    importTaskLog.setStartTime(new Date());
                    importTaskLog.setSubtaskId(importSubTask.getSubtaskId());
                    importTaskLog.setTaskLogId(StringUtil.concat(new StringBuffer(), PrefixConstants.TASK_LOG_PREFIX, "_", String.valueOf(SnowFlakeUtil.getNextId())));

                    //截取文件路径
                    String filePath = fullFileName.substring(0, fullFileName.lastIndexOf("/"));

                    //============获取ver文件============
                    String verifyFile = null;
                    try {
                        verifyFile = FileUtil.getFile(fullFileName, ExpConstants.DAT_FILE_NOT_EXISTS_EXP);
                        if ("".equals(verifyFile)) {
                            importTaskLog.setFilePath(filePath);
                            importTaskLog.setFileName(FileUtil.getFileName(fullFileName));
                            importTaskLog.setEndTime(new Date());
                            importTaskLog.setTaskStatus(String.valueOf(TaskStatusEnum.FAIL.getCode()));
                            importTaskLog.setErrorMsg(ExpConstants.BLANK_VER_FILE_EXP);
                            Long id = importSubTask.getId();
                            httpSupport.send(ReturnVo.ok()
                                    .put("flag", "get-ver-fail")
                                    .put("id", id)
                                    .put("importTaskLog", importTaskLog)
                            );
                        }
                    } catch (Exception e) {
                        importTaskLog.setFilePath(filePath);
                        importTaskLog.setFileName(FileUtil.getFileName(fullFileName));
                        importTaskLog.setEndTime(new Date());
                        importTaskLog.setTaskStatus(String.valueOf(TaskStatusEnum.FAIL.getCode()));
                        importTaskLog.setErrorMsg(ExpConstants.VER_FILE_NOT_EXISTS_EXP);
                        Long id = importSubTask.getId();
                        httpSupport.send(ReturnVo.ok()
                                .put("flag", "get-ver-fail")
                                .put("id", id)
                                .put("importTaskLog", importTaskLog)
                        );
                        log.info("------ 校验失败 ------");
                    }

                    if (!StringUtils.isEmpty(verifyFile)) {
                        //对dat文件转换
                        List<VerifyFile> verifyFileList = StringUtil.toList(verifyFile);

                        //从verfilelist中获取每一个失败的dat文件进行处理
                        if (returnDto.getFileNames() != null) {
                            verifyFileList = FileUtil.getFailFileList(verifyFileList, fileNames);
                        }

                        //============对dat文件校验，并且完成dat文件校验以后返回标识位，只要有一个dat失败就代表子任务异常============
                        boolean flag = this.verifyAndImportDatFile(verifyFileList, importTaskLog, importSubTask, filePath);

                        //完成dat校验并成功导入数据以后以后返回isSuccess和返回给服务端finish标识
                        httpSupport.send(ReturnVo.ok()
                                .put("flag", "finish")
                                .put("id", importSubTask.getId())
                                .put("isSuccess", flag)
                        );
                    }
                } catch (Exception ignore) {}
            });
        }
    }

    public boolean verifyAndImportDatFile(List<VerifyFile> verifyFileList, ImportTaskLog importTaskLog, ImportSubTask importSubTask, String filePath) throws Exception {
        boolean flag = true;
        //对每一行记录大小、行数进行校验
        for (VerifyFile verFile : verifyFileList) {
            //如果是失败的datfile或者是第一次执行的datfile就执行以下程序
            importTaskLog.setErrorMsg(null);
            importTaskLog.setFileName(verFile.getDatFileName());
            importTaskLog.setFileSize(verFile.getFileBytesSize());
            importTaskLog.setFileRecordRows(verFile.getFileRecords());
            Long id = importSubTask.getId();

            //判断dat文件是否为空，为空就不执行
            String datFileContext = FileUtil.getFile(filePath + "/" + verFile.getDatFileName(), ExpConstants.DAT_FILE_NOT_EXISTS_EXP);
            boolean emptyFile = FileUtil.isEmptyFile(datFileContext, filePath + "/" + verFile.getDatFileName());

            if (Boolean.FALSE.equals(emptyFile)) {
                //===============对dat文件进行校验=================
                boolean isVerifyDatFileFalse = subTaskSupport.verifyDatFile(importTaskLog, filePath, verFile, id);
                if (!isVerifyDatFileFalse) {
                    flag = isVerifyDatFileFalse;
                    continue;
                }

                //dat文件校验成功以后生成ctl文件
                String ctlFileName = FileUtil.createCtlFile(verFile, importSubTask.getCtlContext(), filePath);

                //============http调用访问sqlldr服务器============
                boolean isImportDataFalse = subTaskSupport.importDatFile(ctlFileName, importSubTask, filePath, importTaskLog, verFile.getDatFileName());
                if (!isImportDataFalse) {
                    flag = isImportDataFalse;
                    continue;
                }

                //成功以后生成结果日志并返回执行结果
                importTaskLog.setFilePath(filePath);
                importTaskLog.setFileName(verFile.getDatFileName());
                importTaskLog.setFileSize(verFile.getFileBytesSize());
                importTaskLog.setFileRecordRows(verFile.getFileRecords());
                importTaskLog.setTaskStatus(String.valueOf(TaskStatusEnum.SUCCESS.getCode()));
                importTaskLog.setEndTime(new Date());
                httpSupport.send(ReturnVo.ok()
                        .put("id", id)
                        .put("importTaskLog", importTaskLog)
                        .put("flag", "success")
                        .put("enable", "true")
                );
            } else {
                log.warn("处理dat文件为空");
                importTaskLog.setErrorMsg("dat文件为空");
                importTaskLog.setFilePath(filePath);
                importTaskLog.setFileName(verFile.getDatFileName());
                importTaskLog.setFileSize(verFile.getFileBytesSize());
                importTaskLog.setFileRecordRows(verFile.getFileRecords());
                importTaskLog.setTaskStatus(String.valueOf(TaskStatusEnum.SUCCESS.getCode()));
                importTaskLog.setEndTime(new Date());
                httpSupport.send(ReturnVo.ok()
                        .put("id", id)
                        .put("importTaskLog", importTaskLog)
                        .put("flag", "success")
                );
            }
        }
        return flag;
    }
}
